package com.atguigu.exam.service.impl;


import com.atguigu.exam.entity.Category;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.exception.ExamException;
import com.atguigu.exam.mapper.CategoryMapper;
import com.atguigu.exam.mapper.QuestionMapper;
import com.atguigu.exam.service.CategoryService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.Count;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper,Category> implements CategoryService {
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private QuestionMapper questionMapper;

    @Override
    public List<Category> getCategoriesWithCount() {
        //1.从categories里获取基础题目分类并升序排序
        List<Category> categories = categoryMapper.selectList(new LambdaQueryWrapper<Category>().orderByAsc(Category::getSort));

        //2.调用方法将每个分类中题目数量填充到该分类中
        fillQuestionCount(categories);


        return categories;
    }

    @Override
    public List<Category> getCategoryTree() {
        //获取所有分类列表,按照sort排序
        List<Category> categories = categoryMapper.selectList(new LambdaQueryWrapper<Category>().orderByAsc(Category::getSort));
        //获取分类下的题目数
        fillQuestionCount(categories);
        //构建分类树结构
        List<Category> categoryTree = buildCategoryTree(categories);
        return categoryTree;
    }

    @Override
    public void saveCategory(Category category) {
        //根据父分类id和要添加的分类的名字查询父分类下是否已存在该分类,若存在则抛异常,如不存在则添加
        //创建lambdaquertWrapper
        LambdaQueryWrapper<Category> categoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
        //封装查询条件
        categoryLambdaQueryWrapper.eq(Category::getParentId,category.getParentId()).eq(Category::getName,category.getName());
        //调用查询条件
        Category isExitCategory = baseMapper.selectOne(categoryLambdaQueryWrapper);
        //判断是否重复
        if (isExitCategory != null){
            //获取父id
            Long parentId = category.getParentId();
            //获取父Name
            Category parentCategory = baseMapper.selectById(parentId);
            //抛异常父分类下已存在
            throw new ExamException(111,"父分类<"+parentCategory.getName()+">下已存在<"+isExitCategory.getName()+">分类,请重新输入分类的名称");
        }
        //保存该分类
        baseMapper.insert(category);

    }

    @Override
    public void updateCategoryById(Category category) {
        // 根据当前分类的父id查询所有的子分类
        List<Category> childrenCategories = baseMapper.selectList(new LambdaQueryWrapper<Category>().eq(Category::getParentId, category.getParentId()));
        //获取所有子类的名字,把子类用流转换成名字集合
        List<String> childrenCategoryNames = childrenCategories.stream().map(Category::getName).collect(Collectors.toList());
        //遍历集合判断要更新的名字是否在子分类名字中
        if (childrenCategoryNames.contains(category.getName())){
            //判断要更新的是同名同id
        }
    }

    @Override
    public void removeCategoryById(Long id) {
        //删除分类,如果分类下有题目不能删除分类
        //判断当前分类是否有子分类
        Long childrenCategoryCount = baseMapper.selectCount(new LambdaQueryWrapper<Category>().eq(Category::getParentId, id));
        //分类下是否有题目
        Long questionCount = questionMapper.selectCount(new LambdaQueryWrapper<Question>().eq(Question::getCategoryId, id));
        if (childrenCategoryCount > 0 || questionCount > 0){
            //有子不能删
            throw  new ExamException(333,"该分类下有子类或题目,不能删除");
        }
        baseMapper.deleteById(id);

    }

    //写一个私有方法构建分类树
    private List<Category> buildCategoryTree(List<Category> categories) {
        //按照parent_id分组，获取每个父分类下的子分类列表,把categories通过stream流收集分组得到一个parentIdMap
        Map<Long, List<Category>> parentIdMap = categories.stream().collect(Collectors.groupingBy(Category::getParentId));
        //遍历所有的分类
       categories.forEach(category -> {
            //获取当前分类的id
           Long id = category.getId();
           //根据当前分类的id从Map中获取子分类列表
           List<Category> childrenCategoties = parentIdMap.getOrDefault(id, new ArrayList<>());
           //将子分类列表设置到分类对象中
            category.setChildren(childrenCategoties);
            //获取所有子分类的题目数量之和,把Category转成Long
           Long childrenSumQuestionCount = childrenCategoties.stream().mapToLong(c -> c.getCount() != null ? c.getCount() : 0L).sum();
           //获取当前类型的题目的数量
           Long count = category.getCount();
           //设置当前分类题目的数量是子分类题目的数量之和加上当前分类的题目数量
           category.setCount(count+childrenSumQuestionCount);
       });

        //获取顶级分类列表，即parent_id为0的分类
        List<Category> categoryTree = categories.stream().filter(category -> category.getParentId() == 0).collect(Collectors.toList());
        return categoryTree;
    }

    //写一个私有方法填充题目数
    private void fillQuestionCount(List<Category> categories){
        //1.一次性查出所有分类的题目数量
        List<Map<Long,Object>> questionCountList = questionMapper.getCategoryQuestionCount();
        System.out.println("List<Map>: "+questionCountList);
        //2.将查询结果从List<Map>转换成Map<categoryId,count>便于快速查找
        Map<Long, Long> countMap = questionCountList.stream().collect(Collectors.toMap(
                map -> Long.valueOf(map.get("category_id").toString()),
                map -> Long.valueOf(map.get("count").toString())
        ));
        System.out.println(countMap);
        //3.遍历分类列表,为每个分类设置对应的题目数量
        categories.forEach(category -> category.setCount(countMap.getOrDefault(category.getId(),0L)));
    }
}